package com.atguigu.jxc.controller;

import com.atguigu.jxc.dao.SaleListDao;
import com.atguigu.jxc.dao.UserDao;
import com.atguigu.jxc.domain.ServiceVO;
import com.atguigu.jxc.domain.SuccessCode;
import com.atguigu.jxc.entity.*;
import com.atguigu.jxc.service.*;
import com.atguigu.jxc.util.BigDecimalUtil;
import com.atguigu.jxc.util.DateUtil;
import com.atguigu.jxc.util.ResultUtil;
import com.atguigu.jxc.util.StringUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.Mapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.ToDoubleFunction;

@RestController
public class GoodsController {

    @Autowired
    private GoodsService goodsService;
    @Autowired
    private DamageListService damageListService;
    @Autowired
    private DamageListGoodsService damageListGoodsService;
    @Autowired
    private UserDao userDao;
    @Autowired
    private OverflowListService overflowListService;
    @Autowired
    private OverflowListGoodsService overflowListGoodsService;

    @Autowired
    private PurchaseListService purchaseListService;
    @Autowired
    private PurchaseListGoodsService purchaseListGoodsService;
    @Autowired
    private SaleListDao saleListDao;

    /**
     * 当前库存查询
     *
     * @param page        第几页
     * @param rows        每页显示的数量
     * @param codeOrName  商品编码或名称
     * @param goodsTypeId 商品类别id
     * @return map
     */
    @PostMapping("/goods/listInventory")
    public Map<String, Object> listInventory(Integer page, Integer rows, String codeOrName, Integer goodsTypeId) {
        Map<String, Object> map = goodsService.listInventory(page, rows, codeOrName, goodsTypeId);
        return map;
    }

    /**
     * 查询所有商品信息
     *
     * @param page        第几页
     * @param rows        每页显示的数量
     * @param goodsName   商品编码或名称
     * @param goodsTypeId 商品类别id
     * @return map
     */
    @PostMapping("/goods/list")
    public Map<String, Object> list(Integer page, Integer rows, String goodsName, Integer goodsTypeId) {
        Map<String, Object> map = goodsService.listInventory(page, rows, goodsName, goodsTypeId);
        return map;
    }

    /**
     * 查询所有的商品分类
     *
     * @return 返回list的json字符串
     */
    @RequestMapping("/goodsType/loadGoodsType")
    public String loadGoodsType() {
        List<Map> GoodsTypeList = goodsService.loadGoodsType();

        Gson gson = new Gson();
        String GoodsTypeListStr = gson.toJson(GoodsTypeList);
        return GoodsTypeListStr;
    }

    /**
     * 查询所有商品单位
     *
     * @return
     */
    @PostMapping("/unit/list")
    public Map<String, Object> unitList() {
        Map<String, Object> map = goodsService.unitList();
        return map;
    }

    /**
     * 新增分类
     *
     * @param goodsTypeName
     * @param pId
     * @return
     */
    @PostMapping("/goodsType/save")
    public ServiceVO goodsTypeSave(String goodsTypeName, Integer pId) {
        ServiceVO serviceVO = goodsService.goodsTypeSave(goodsTypeName, pId);
        return serviceVO;
    }

    /**
     * 删除分类
     *
     * @param goodsTypeId
     * @return
     */
    @PostMapping("/goodsType/delete")
    public ServiceVO goodsTypeDelete(Integer goodsTypeId) {
        return goodsService.goodsTypeDelete(goodsTypeId);
    }

    /**
     * 商品添加或修改
     *
     * @param goodsId
     * @param goods
     * @return
     */
    @PostMapping("/goods/save")
    public ServiceVO save(Integer goodsId, Goods goods) {
        return goodsService.saveGoods(goodsId, goods);
    }


    /**
     * 生成商品编码
     *
     * @return
     */
    @PostMapping("/goods/getCode")
    public ServiceVO getCode() {
        String goodsCodeStr = goodsService.getCode();

        return new ServiceVO(SuccessCode.SUCCESS_CODE, SuccessCode.SUCCESS_MESS, goodsCodeStr);
    }


    /**
     * 删除某个商品
     *
     * @param goodsId
     * @return
     */
    @PostMapping("/goods/delete")
    public ServiceVO deleteGoods(Integer goodsId) {
        return goodsService.deleteGoods(goodsId);
    }

    /**
     * 无库存商品列表展示（可以根据商品名称或编码查询）
     *
     * @param page
     * @param rows
     * @param nameOrCode
     * @return
     */
    @PostMapping("/goods/getNoInventoryQuantity")
    public Map<String, Object> getNoInventoryQuantity(Integer page, Integer rows, String nameOrCode) {
        Map<String, Object> map = goodsService.getNoOrHasInventoryQuantity(page, rows, nameOrCode, false);
        return map;
    }

    /**
     * 有库存商品列表展示（可以根据商品名称或编码查询）
     *
     * @param page
     * @param rows
     * @param nameOrCode
     * @return
     */
    @PostMapping("/goods/getHasInventoryQuantity")
    public Map<String, Object> getHasInventoryQuantity(Integer page, Integer rows, String nameOrCode) {
        Map<String, Object> map = goodsService.getNoOrHasInventoryQuantity(page, rows, nameOrCode, true);
        return map;
    }

    /**
     * 修改数量或成本价
     *
     * @param goodsId
     * @param inventoryQuantity
     * @param purchasingPrice
     * @return
     */
    @PostMapping("/goods/saveStock")
    public ServiceVO saveStock(Integer goodsId, Integer inventoryQuantity, double purchasingPrice) {
        Goods goods = new Goods();
        goods.setGoodsId(goodsId);
        goods.setInventoryQuantity(inventoryQuantity);
        goods.setPurchasingPrice(purchasingPrice);
        goodsService.update(goods, new UpdateWrapper<Goods>().eq("goods_id", goodsId));
        // UPDATE t_goods SET goods_id=?, inventory_quantity=?, last_purchasing_price=?, purchasing_price=?, selling_price=? WHERE null=?
//        goodsService.updateById(goods); 错误： 没有一个id属性，有goods_id
        return new ServiceVO(SuccessCode.SUCCESS_CODE, SuccessCode.SUCCESS_MESS, null);
    }

    /**
     * 删除库存（要判断商品状态 入库、有进货和销售单据的不能删除）
     *
     * @return
     */
    @PostMapping("/goods/deleteStock")
    public ServiceVO deleteStock(Integer goodsId) {
        return goodsService.deleteGoods(goodsId);
    }

    /**
     * 保存报损单
     *
     * @param damageNumber       报损单号,前端生成
     * @param damageList
     * @param damageListGoodsStr
     * @return
     */
    @PostMapping("/damageListGoods/save")
    @Transactional(rollbackFor = Exception.class)
    public ServiceVO saveDamageListGoods(String damageNumber, DamageList damageList, String damageListGoodsStr) {
        // 获取当前登录的用户id
        String userName = (String) SecurityUtils.getSubject().getPrincipal();
        //根据用户名查询用户信息
        User user = userDao.findUserByName(userName);
        Integer userId = user.getUserId();

        // 保存报损表单
        damageList.setDamageNumber(damageNumber);
        damageList.setUserId(userId);
        damageListService.save(damageList);
        // 保存报损表单对应的商品
        Gson gson = new Gson();
        List<DamageListGoods> damageListGoodsList = gson.fromJson(damageListGoodsStr, new TypeToken<List<DamageListGoods>>() {
        }.getType());

        for (DamageListGoods damageListGoods : damageListGoodsList) {
            damageListGoods.setDamageListId(damageList.getDamageListId());
        }

        damageListGoodsService.saveBatch(damageListGoodsList);

        return new ServiceVO(SuccessCode.SUCCESS_CODE, SuccessCode.SUCCESS_MESS, null);
    }


    /**
     * 新增报溢单
     *
     * @param overflowNumber       报溢单号
     * @param overflowList
     * @param overflowListGoodsStr
     * @return
     */
    @PostMapping("/overflowListGoods/save")
    @Transactional(rollbackFor = Exception.class)
    public ServiceVO saveOverflowListGoods(String overflowNumber, OverflowList overflowList, String overflowListGoodsStr) {
        // 获取当前登录的用户id
        String userName = (String) SecurityUtils.getSubject().getPrincipal();
        //根据用户名查询用户信息
        User user = userDao.findUserByName(userName);
        Integer userId = user.getUserId();

        // 保存报溢表单
        overflowList.setOverflowNumber(overflowNumber);
        overflowList.setUserId(userId);
        overflowListService.save(overflowList);
        // 保存报溢表单对应的商品
        Gson gson = new Gson();
        List<OverflowListGoods> overflowListGoodsList = gson.fromJson(overflowListGoodsStr, new TypeToken<List<OverflowListGoods>>() {
        }.getType());

        for (OverflowListGoods overflowListGoods : overflowListGoodsList) {
            overflowListGoods.setOverflowListId(overflowList.getOverflowListId());
        }

        overflowListGoodsService.saveBatch(overflowListGoodsList);

        return new ServiceVO(SuccessCode.SUCCESS_CODE, SuccessCode.SUCCESS_MESS, null);
    }

    /**
     * 查询所有 当前库存量 小于 库存下限的商品信息
     *
     * @return
     */
    @PostMapping("/goods/listAlarm")
    public Map<String, Object> listAlarm() {
        return goodsService.listAlarm();
    }

    /**
     * 报损单查询
     *
     * @param sTime
     * @param eTime
     * @return
     */
    @PostMapping("/damageListGoods/list")
    public Map<String, Object> damageListGoods(String sTime, String eTime) {
        QueryWrapper<DamageList> wrapper = new QueryWrapper<>();

        wrapper.ge("damage_date", sTime).le("damage_date", eTime);
        List<DamageList> list = damageListService.list(wrapper);
        // 设置trueName登录用户名
        for (DamageList damageList : list) {
            Integer userId = damageList.getUserId();
            String trueName = userDao.getUserById(userId).getTrueName();
            damageList.setTrueName(trueName);
        }
        return ResultUtil.toRowsMap(list);

    }

    /**
     * 查询报损单商品信息
     *
     * @param damageListId
     * @return
     */
    @PostMapping("/damageListGoods/goodsList")
    public Map<String, Object> getDamageListGoods(Integer damageListId) {
        QueryWrapper<DamageListGoods> wr = new QueryWrapper<>();
        wr.eq("damage_list_id", damageListId);
        List<DamageListGoods> damageListGoodsList = damageListGoodsService.list(wr);

        Map<String, Object> map = ResultUtil.toRowsMap(damageListGoodsList);
        return map;
    }

    /**
     * 报溢单查询
     *
     * @param sTime
     * @param eTime
     * @return
     */
    @PostMapping("/overflowListGoods/list")
    public Map<String, Object> getOverflowListList(String sTime, String eTime) {
        QueryWrapper<OverflowList> wrapper = new QueryWrapper<>();

        wrapper.ge("overflow_date", sTime).le("overflow_date", eTime);
        List<OverflowList> list = overflowListService.list(wrapper);
        // 设置trueName登录用户名
        for (OverflowList overflowList : list) {
            Integer userId = overflowList.getUserId();
            String trueName = userDao.getUserById(userId).getTrueName();
            overflowList.setTrueName(trueName);
        }
        return ResultUtil.toRowsMap(list);
    }

    /**
     * 报溢单商品信息
     *
     * @param overflowListId
     * @return
     */
    @PostMapping("/overflowListGoods/goodsList")
    public Map<String, Object> getOverflowListGoods(Integer overflowListId) {
        QueryWrapper<OverflowListGoods> wr = new QueryWrapper<>();
        wr.eq("overflow_list_id", overflowListId);
        List<OverflowListGoods> overflowListGoods = overflowListGoodsService.list(wr);

        Map<String, Object> map = ResultUtil.toRowsMap(overflowListGoods);
        return map;
    }

    /**
     * 进货单保存
     *
     * @param purchaseNumber
     * @param purchaseList
     * @param purchaseListGoodsStr
     * @return
     */
    @PostMapping("/purchaseListGoods/save")
    public ServiceVO savePurchaseList(String purchaseNumber, PurchaseList purchaseList, String purchaseListGoodsStr) {
        return goodsService.savePurchaseList(purchaseNumber, purchaseList, purchaseListGoodsStr);
    }

    /**
     * 退货单保存
     *
     * @param returnNumber
     * @param returnList
     * @param returnListGoodsStr
     * @return
     */
    @PostMapping("/returnListGoods/save")
    public ServiceVO saveReturnListGoods(String returnNumber, ReturnList returnList, String returnListGoodsStr) {
        return goodsService.saveReturnListGoods(returnNumber, returnList, returnListGoodsStr);
    }

    /**
     * 进货单列表展示（可条件查询：单据号模糊、供应商、是否付款和日期区间）
     *
     * @param purchaseNumber
     * @param supplierId
     * @param state
     * @param sTime
     * @param eTime
     * @return
     */
    @PostMapping("/purchaseListGoods/list")
    public Map<String, Object> getPurchaseListList(String purchaseNumber, Integer supplierId, Integer state, String sTime, String eTime) {
        return purchaseListService.getPurchaseListGoodsList(purchaseNumber, supplierId, state, sTime, eTime);
    }

    /**
     * 查询进货单商品信息
     *
     * @param purchaseListId
     * @return
     */
    @PostMapping("/purchaseListGoods/goodsList")
    public Map<String, Object> getPurchaseListGoodsList(Integer purchaseListId) {
        QueryWrapper<PurchaseListGoods> wrapper = new QueryWrapper<PurchaseListGoods>();
        wrapper.eq("purchase_list_id", purchaseListId);
        List<PurchaseListGoods> list = purchaseListGoodsService.list(wrapper);
        Map<String, Object> map = ResultUtil.toRowsMap(list);
        return map;
    }

    /**
     * 进货单删除
     *
     * @param purchaseListId
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/purchaseListGoods/delete")
    public ServiceVO deletePurchaseList(Integer purchaseListId) {
        // 先删除进货单商品
        QueryWrapper<PurchaseListGoods> wrapper1 = new QueryWrapper<PurchaseListGoods>();
        wrapper1.eq("purchase_list_id", purchaseListId);
        purchaseListGoodsService.remove(wrapper1);

        // 再删除进货单
        QueryWrapper<PurchaseList> wrapper2 = new QueryWrapper<PurchaseList>();
        wrapper2.eq("purchase_list_id", purchaseListId);
        purchaseListService.remove(wrapper2);

        return new ServiceVO(SuccessCode.SUCCESS_CODE, SuccessCode.SUCCESS_MESS, null);
    }

    /**
     * 退货单列表展示（可条件查询：单据号模糊、供应商、是否付款和日期区间）
     *
     * @param returnNumber
     * @param supplierId
     * @param state
     * @param sTime
     * @param eTime
     * @return
     */
    @PostMapping("/returnListGoods/list")
    public Map<String, Object> getReturnListList(String returnNumber, Integer supplierId, Integer state, String sTime, String eTime) {
        return goodsService.getReturnListList(returnNumber, supplierId, state, sTime, eTime);
    }

    /**
     * 修改进货单付款状态为已付款
     *
     * @param purchaseListId
     * @return
     */
    @PostMapping("/purchaseListGoods/updateState")
    public ServiceVO updateStateOfPurchaseList(Integer purchaseListId) {
        PurchaseList purchaseList = new PurchaseList();
        purchaseList.setPurchaseListId(purchaseListId);
        purchaseList.setState(1);
        purchaseListService.updateById(purchaseList);

        return new ServiceVO(SuccessCode.SUCCESS_CODE, SuccessCode.SUCCESS_MESS, null);
    }

    /**
     * 按日统计接口 日销售总额、成本总额、盈利总额
     *
     * @param sTime
     * @param eTime
     * @return
     */
    @PostMapping("/saleListGoods/getSaleDataByDay")
    public String getSaleDataByDay(String sTime, String eTime) throws Exception {
        // 起始时间到结束时间的所有天
        List<String> timeSlotByDay = DateUtil.getTimeSlotByDay(sTime, eTime);
        // 封装结果的mapList
        List<Map<String, Object>> mapList = new ArrayList<>();
        for (String day : timeSlotByDay) {
            // 采购清单列表
            List<PurchaseList> purchase_date = purchaseListService.list(new QueryWrapper<PurchaseList>().eq("purchase_date", day));
            // 销售清单列表
            List<SaleList> sale_date = saleListDao.selectList(new QueryWrapper<SaleList>().eq("sale_date", day));
            // 实付销售金额
            double amountPaidSale = 0;
            if (!CollectionUtils.isEmpty(sale_date)) {
                amountPaidSale = sale_date.stream().mapToDouble(SaleList::getAmountPaid).sum();
            }

            // 实付成本金额
            double amountPaidPurchase = 0;
            if (!CollectionUtils.isEmpty(purchase_date)) {
                amountPaidPurchase = purchase_date.stream().mapToDouble(PurchaseList::getAmountPaid).sum();
            }
            // 盈利总额
            double profit = amountPaidSale - amountPaidPurchase;
            HashMap<String, Object> map = new HashMap<>();
            map.put("date", day);
            map.put("saleTotal", amountPaidSale);
            map.put("purchasingTotal", amountPaidPurchase);
            map.put("profit", profit);

            mapList.add(map);
        }
        Gson gson = new Gson();
        String jsonStr = gson.toJson(mapList);
        return jsonStr;
    }

    /**
     * 按月统计月销售总额、成本总额、盈利总额数据列表
     * @param sTime
     * @param eTime
     * @return
     */
    @PostMapping("/saleListGoods/getSaleDataByMonth")
    public String getSaleDataByMonth(String sTime, String eTime) throws Exception {
        // 起始时间到结束时间的所有月
        List<String> timeSlotByMonth = DateUtil.getTimeSlotByMonth(sTime, eTime);
        // 封装结果的mapList
        List<Map<String, Object>> mapList = new ArrayList<>();
        for (String month : timeSlotByMonth) {
            // 采购清单列表
            List<PurchaseList> purchase_date = purchaseListService.list(new QueryWrapper<PurchaseList>().likeRight("purchase_date", month));
            // 销售清单列表
            List<SaleList> sale_date = saleListDao.selectList(new QueryWrapper<SaleList>().likeRight("sale_date", month));

            // 实付销售金额
            double amountPaidSale = 0;
            if (!CollectionUtils.isEmpty(sale_date)) {
                amountPaidSale = sale_date.stream().mapToDouble(SaleList::getAmountPaid).sum();
            }

            // 实付成本金额
            double amountPaidPurchase = 0;
            if (!CollectionUtils.isEmpty(purchase_date)) {
                amountPaidPurchase = purchase_date.stream().mapToDouble(PurchaseList::getAmountPaid).sum();

            }
            // 盈利总额
            double profit = amountPaidSale - amountPaidPurchase;
            HashMap<String, Object> map = new HashMap<>();
            map.put("date", month);
            map.put("saleTotal", amountPaidSale);
            map.put("purchasingTotal", amountPaidPurchase);
            map.put("profit", profit);

            mapList.add(map);

        }
        Gson gson = new Gson();
        String jsonStr = gson.toJson(mapList);
        return jsonStr;

    }
}
